// Copyright (c) 2008 Matthew Johnson
// Licensed under the MIT License (see license.txt)
package actionml.core {
	import actionml.Global;
	
	public class NumberMethods {
		public static function initialize() {
			Global.initializeExtension(NumberMethods, Number);
		}
		public static var instanceMethods:Object = {
			evaluateExpression: function(context:Object) {
				return this;
			},
			compileExpression: function() {
				return [this];
			},
			evaluateMethod: function(method:String) {
				var match:Object;
				if (method.match(/^round\d+Decimals$/)){
					match = method.match(/^round(?P<decimals>\d+)Decimals$/);
					return this.toFixed(match.decimals);
				} else if (method.match(/^round\d+Zeros$/)){
					match = method.match(/^round(?P<zeros>\d+)Zeros$/);
					var power:int = Math.pow(10, match.zeros);
					return Math.round(this / power) * power;
				}
			},
			squared: function() {
				return this * this;
			},
			
			
			clampRange: function(minValue:Number, maxValue:Number) {
				if (this < minValue) {
					return minValue;
				} else if (this > maxValue) {
					return maxValue;
				} else {
					return this;
				} 
			},
			
			toDegrees: function() {
				 return this * 180 / Math.PI;
			},
			toRadians: function() {
				 return this * Math.PI / 180;
			},
			
			normalizeRadiansToCycle: function() {
				if (this > 0) {
					return this % Math.PI;
				} else {
					return (Math.PI * 2) + this % Math.PI;
				}
			},
			normalizeRadiansToQuadrant: function() {
				var angle:Number = this.normalizeRadiansToCycle();
				var halfPI:Number = Math.PI / 2;
				if (angle == 0 || angle == Math.PI) return 0;
				if (angle == halfPI || angle == Math.PI + halfPI) return halfPI;
				if (angle < halfPI) {
					return angle;
				} else if (angle > halfPI && angle < Math.PI) {
					return halfPI - (angle - halfPI);
				} else if (angle > Math.PI && angle < (Math.PI + halfPI)) {
					return angle - Math.PI;
				} else {
					return halfPI - (angle - (Math.PI + halfPI));
				}
			},
			normalizeRadiansToOctant: function() { 
				var normalizedToQuadrant:Number = this.normalizeRadiansToQuadrant();
				if (normalizedToQuadrant <= (Math.PI / 4)) {
					return normalizedToQuadrant;
				} else {
					return (Math.PI / 2) - normalizedToQuadrant;
				}
			},
			
			toPaddedString: function(digits:int, padding:String="0") {
				var s:String = this.toString();
				while (s.length < digits) {
					s = padding + s;
				}
				return s;
			},
			formatMoney: function() {
				return "$" + this["formatWithCommas"]().replace(/(\.\d\d)\d+/, "$1");
			},
			formatWithCommas: function(pad:Boolean=false) {	
				var result:String;
				var num:Number = Math.abs(this);
				var sign:String = "";
				if (this < 0) {
					sign = "-"
				}
				if (num >= 1000000) {
					result = sign + Math.floor(num / 1000000)["formatWithCommas"]() + ",";
					if (num % 1000000 < 1000) {
						result += "000,"
					}
					return result + (num % 1000000)["formatWithCommas"](true);
				}
				if (num >= 1000) {
					result =  "," + (num % 1000)["formatWithCommas"](true);
					if (pad) {
						return sign + Math.floor(num / 1000).toString()["padFront"](3, "0") + result;	
					} else {
						return sign + Math.floor(num / 1000) + result;
					}
				}
				if (num % 1 != 0) {
					result = sign + Math.floor(num / 1) + (Math.round((num % 1) * 100) / 100).toString().replace(/^0/, "")["padBack"](3, "0");
					if (pad) {
						return result.padFront(6, "0");	
					} else {
						return result;
					}
				} else {
					result = sign + Math.floor(num / 1);
					if (pad) {
						return result.padFront(3, "0");	
					} else {
						return result;
					}
				}
			}
		};
	}
}